#pragma once

#include <iostream>
#include <string>
#include <strings.h>
#include <ctype.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include "Protocal.hpp"
#include "Util.hpp"

#define BUF_NUM 1024

namespace tcpc
{
    const Request Parse(const std::string &line) // 1+1
    {
        int status = 0; // 0:操作符前 1:操作符 2:操作符后
        int i = 0;
        int len = line.size();
        std::string left, right;
        char oper;
        while (i < len)
        {
            switch (status)
            {
            case 0:
            {
                if (!isdigit(line[i]))
                {
                    oper = line[i];
                    status = 1;
                }
                else
                    left.push_back(line[i++]);
            }
            break;
            case 1:
                i++;
                status = 2;
                break;
            case 2:
                right.push_back(line[i++]);
                break;
            }
        }
        int x = std::stoi(left);
        int y = std::stoi(right);
        Request req(x, y, oper);
        return req;
    }

    class CalClient
    {
    public:
        CalClient(const std::string &serverip, const uint16_t &serverport)
            : _sock(-1), _serverip(serverip), _serverport(serverport)
        {
        }
        void initCalClient()
        {
            _sock = socket(AF_INET, SOCK_STREAM, 0);
            if (_sock < 0)
            {
                std::cout << "socket create error" << std::endl;
                exit(1);
            }
            std::cout << "socket create success" << std::endl;
        }
        void runCalClient()
        {
            struct sockaddr_in server;
            server.sin_family = AF_INET;
            server.sin_addr.s_addr = inet_addr(_serverip.c_str());
            server.sin_port = htons(_serverport);
            if (connect(_sock, (struct sockaddr *)&server, sizeof(server)) != 0)
            {
                std::cout << "socket connect error" << std::endl;
                exit(2);
            }
            else
            {
                std::cout << "socket connect success" << std::endl;
                std::string msg;
                while (true)
                {
                    std::cout << "MyCal <<< ";
                    std::getline(std::cin, msg);
                    // eg:
                    // msg:1+1
                    Request req = Parse(msg);
                    std::string req_content;
                    req.serialization(&req_content);
                    std::string send_req = enLength(req_content);
                    std::cout << "send_req: \n"
                              << send_req << std::endl;
                    write(_sock, send_req.c_str(), send_req.size());
                    std::string text, inbuffer;
                    for (;;)
                    {
                        char buffer[BUF_NUM];
                        ssize_t n = recv(_sock, buffer, sizeof(buffer) - 1, 0);
                        // std::cout << "n = " << n << std::endl;
                        if (n > 0)
                        {
                            buffer[n] = 0;
                            inbuffer += buffer;
                            if (ParseOneMsg(&text, inbuffer))
                            {
                                std::string content;
                                if (!deLength(text, &content))
                                    return;
                                Response resp;
                                resp.deserialization(content);
                                std::cout << resp._exitcode << " " << resp._result << std::endl;
                                break;
                            }
                        }
                        else if (n == 0)
                        {
                            std::cout << "server close" << std::endl;
                            exit(-1);
                        }
                        else
                        {
                            if (errno == EAGAIN || errno == EWOULDBLOCK)
                                break;
                            else if (errno == EINTR)
                                continue;
                            // else
                            //     std::cout << "bug" << std::endl;
                        }
                    }
                }
            }
        }
        ~CalClient()
        {
            close(_sock);
        }

    private:
        std::string _serverip;
        uint16_t _serverport;
        int _sock; // 客户端套接字，用于与服务端进行链接
    };
}
